﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FPNN
{
    public struct Fix16
    {
        public Int16 RawValue;
        public const byte SHIFT_AMOUNT = 8; //12 is 4096

        public const Int16 One = 1 << SHIFT_AMOUNT;

        #region Constructors
        public static Fix16 Create(Int16 rawValue, bool UseMultiple)
        {
            Fix16 fInt;
            fInt.RawValue = rawValue;
            if (UseMultiple)
                fInt.RawValue = (Int16)(fInt.RawValue << SHIFT_AMOUNT);
            return fInt;
        }

        public static Fix16 Create(double value)
        {
            Fix16 fInt;
            value *= (double)One;
            fInt.RawValue = (Int16)Math.Round(value);
            return fInt;
        }
        
        public static Fix16 Parse(string value)
        {            
            return Fix16.Create(Double.Parse(value));
        }
        #endregion

        public Int16 IntegerPart
        {
            get { return (Int16)(this.RawValue >> SHIFT_AMOUNT); }
        }

        public Int16 ToInt16()
        {
            return (Int16)(this.RawValue >> SHIFT_AMOUNT);
        }

        public double ToDouble()
        {
            return (double)this.RawValue / (double)One;
        }        

        public Fix16 Inverse
        {
            get { return Fix16.Create((Int16)(-this.RawValue), false); }
        }

        #region *
        public static Fix16 operator *(Fix16 one, Fix16 other)
        {
            Fix16 fInt;
            fInt.RawValue = (Int16)((one.RawValue * other.RawValue) >> SHIFT_AMOUNT);
            return fInt;
        }       
        #endregion

        #region /
        public static Fix16 operator /(Fix16 one, Fix16 other)
        {
            Fix16 fInt;
            fInt.RawValue = (Int16)((one.RawValue << SHIFT_AMOUNT) / (other.RawValue));
            return fInt;
        }
        #endregion

        #region %
        public static Fix16 operator %(Fix16 one, Fix16 other)
        {
            Fix16 fInt;
            fInt.RawValue = (Int16)((one.RawValue) % (other.RawValue));
            return fInt;
        }
        #endregion

        #region +
        public static Fix16 operator +(Fix16 one, Fix16 other)
        {
            Fix16 fInt;
            fInt.RawValue = (Int16)(one.RawValue + other.RawValue);
            return fInt;
        }
        #endregion

        #region -
        public static Fix16 operator -(Fix16 one, Fix16 other)
        {
            Fix16 fInt;
            fInt.RawValue = (Int16)(one.RawValue - other.RawValue);
            return fInt;
        }        
        #endregion

        #region ==
        public static bool operator ==(Fix16 one, Fix16 other)
        {
            return one.RawValue == other.RawValue;
        }
        public static bool operator ==(Fix16 one, Int16 other)
        {
            return one.ToInt16() == other;
        }
        #endregion

        #region !=
        public static bool operator !=(Fix16 one, Fix16 other)
        {
            return one.RawValue != other.RawValue;
        }
        public static bool operator !=(Fix16 one, Int16 other)
        {
            return one.ToInt16() != other;
        }
        #endregion

        #region >=
        public static bool operator >=(Fix16 one, Fix16 other)
        {
            return one.RawValue >= other.RawValue;
        }
        #endregion

        #region <=
        public static bool operator <=(Fix16 one, Fix16 other)
        {
            return one.RawValue <= other.RawValue;
        }
        #endregion

        #region >
        public static bool operator >(Fix16 one, Fix16 other)
        {
            return one.RawValue > other.RawValue;
        }
        #endregion

        #region <
        public static bool operator <(Fix16 one, Fix16 other)
        {
            return one.RawValue < other.RawValue;
        }
        #endregion

        public static explicit operator Int16(Fix16 src)
        {
            return (Int16)(src.RawValue >> SHIFT_AMOUNT);
        }

        public static explicit operator Fix16(Int16 src)
        {
            return Fix16.Create(src, true);
        }

        public static Fix16 operator <<(Fix16 one, int Amount)
        {
            return Fix16.Create((Int16)(one.RawValue << Amount), false);
        }

        public static Fix16 operator >>(Fix16 one, int Amount)
        {
            return Fix16.Create((Int16)(one.RawValue >> Amount), false);
        }

        public override bool Equals(object obj)
        {
            if (obj is Fix16)
                return ((Fix16)obj).RawValue == this.RawValue;
            else
                return false;
        }

        public override int GetHashCode()
        {
            return RawValue.GetHashCode();
        }

        public override string ToString()
        {
            return this.RawValue.ToString();
        }
    }    
}